<?php

namespace common\models;

use Yii;
use yii\web\IdentityInterface;
use common\db\ActiveRecord;
use common\helpers\Url;
use common\helpers\StringHelper;
use common\helpers\ArrayHelper;
use common\models\user\UserAuthent;
use common\models\user\UserMeta;
use common\validators\MobileValidator;
use yii\validators\EmailValidator;
use yii\filters\RateLimitInterface;

/**
 * 基础用户账号信息模型
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
class BaseUser extends ActiveRecord implements IdentityInterface, RateLimitInterface {

    /**
     * 默认用户状态
     */
    const STATUS_DELETED = 0;

    /**
     * 激活用户状态
     */
    const STATUS_ACTIVE = 10;

    /**
     * Token过期时间2小时
     */
    const TOKEN_EXPIRED = 28800;

    /**
     * Token延迟过期时间2小时
     */
    const TOKEN_EXPIRED_DELAY = 7200;

    /**
     * @inheritdoc
     */
    public static function tableName() {
        return '{{%auth_user}}';
    }

    /**
     * @inheritdoc
     */
    public function rules() {
        return [
            ['status', 'default', 'value' => self::STATUS_ACTIVE],
            ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
        ];
    }

    /**
     * @inheritdoc
     */
    public static function findIdentity($id) {
        return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
    }

    /**
     * @inheritdoc
     */
    public static function findIdentityByAccessToken($token, $type = null) {
        /* @var $security \common\base\Security */
        $security = Yii::$app->security;
        $accessToken = $security->decryptDataByKey($token);
        if ($accessToken) {
            return static::find()->active(self::STATUS_ACTIVE)->andWhere([
                'access_token' => $accessToken,
            ])->andWhere([
                'or',
                ['>', 'expired_at', time()],
                ['expired_at' => 0],
            ])->one();
        }
        Yii::info([
            $token,
            $accessToken,
            $type,
        ], __METHOD__);
        return null;
    }

    /**
     * 根据用户名查询用户信息
     * @param string $username 用户名
     * @return static|null
     */
    public static function findByUsername($username) {
        return static::findOne([
            'username' => $username,
            'status' => self::STATUS_ACTIVE
        ]);
    }

    /**
     * 根据手机号查询用户信息
     * @param string $mobile
     * @return static|null
     */
    public static function findByMobile($mobile) {
        $entra = Yii::$app->security->generatePrivateKey($mobile);
        return static::findOne([
            'mobile' => $entra,
            'status' => self::STATUS_ACTIVE
        ]);
    }

    /**
     * 通过用户名、手机号或者邮箱查询用户
     * @param string $account 用户名、手机号或者邮箱
     * @return static|null
     */
    public static function findByAccount($account) {
        $query = static::find()->active(self::STATUS_ACTIVE);
        $condition = [
            'or',
            ['username' => $account]
        ];
        if (is_numeric($account)) {
            $valid = new MobileValidator();
            if ($valid->validate($account)) {
//                $mobile = Yii::$app->security->generatePrivateKey($account);
                $condition[] = ['mobile' => $account];
            }
        }
        if (strpos($account, '@') !== false) {
            $valid = new EmailValidator();
            if ($valid->validate($account)) {
                $condition[] = ['email' => $account];
            }
        }
        $query->andWhere($condition);
        //$query->debug();
        return $query->one();
    }

    /**
     * 获取账号密码重置token
     * @param string $token password reset token
     * @return static|null
     */
    public static function findByPasswordResetToken($token) {
        if (!static::isPasswordResetTokenValid($token)) {
            return null;
        }
        return static::findOne([
            'password_reset_token' => $token,
            'status' => self::STATUS_ACTIVE,
        ]);
    }

    /**
     * 判断用户密码重置token是否有效
     * @param string $token password reset token
     * @return bool
     */
    public static function isPasswordResetTokenValid($token) {
        if (empty($token)) {
            return false;
        }
        $timestamp = (int) substr($token, strrpos($token, '_') + 1);
        $expire = ArrayHelper::getValue(Yii::$app->params, 'user.passwordResetTokenExpire', 86400);
        return $timestamp + $expire >= time();
    }

    /**
     * @inheritdoc
     */
    public function getId() {
        return $this->getPrimaryKey();
    }

    /**
     * @inheritdoc
     */
    public function getAuthKey() {
        return $this->auth_key;
    }

    /**
     * @inheritdoc
     */
    public function validateAuthKey($authKey) {
        return $this->getAuthKey() === $authKey;
    }

    /**
     * 返回在单位时间内允许的请求的最大数目，例如，[10, 60] 表示在60秒内最多请求10次。
     * @return type
     */
    public function getRateLimit($request, $action) {
        Yii::debug([
            $request->headers
        ]);
        $actionId = str_replace('/', '_', $action->getUniqueId());
        return ArrayHelper::getValue(Yii::$app->params, 'rateLimits.' . $actionId, [20, 1]);
    }

    /**
     * 返回剩余的允许的请求数
     * @param \yii\web\Request $request
     * @param \yii\base\Action $action
     * @return type
     */
    public function loadAllowance($request, $action) {
        Yii::debug([
            $request->headers
        ]);
        return Yii::$app->cache->get($action->getUniqueId() . '_allowance');
    }

    /**
     * 保存请求时的UNIX时间戳
     * @param \yii\web\Request $request the current request
     * @param \yii\base\Action $action the action to be executed
     * @param int $allowance the number of allowed requests remaining.
     * @param int $timestamp the current timestamp.
     */
    public function saveAllowance($request, $action, $allowance, $timestamp) {
        Yii::debug([
            $request->headers
        ]);
        Yii::$app->cache->set($action->getUniqueId() . '_allowance', [
            $allowance, $timestamp
        ]);
    }

    /**
     * 验证账号密码是否正确
     * @param string $password password to validate
     */
    public function validatePassword($password) {
        if ($this->password_hash) {
            return Yii::$app->security->validatePassword($password, $this->password_hash);
        }
        return false;
    }

    /**
     * 设置密码
     * @param string $password
     */
    public function setPassword($password) {
        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
    }

    /**
     * 根据手机号自动生成系统唯一用户名
     * @param string $mobile
     */
    public function setUsernameByMobile($mobile) {
        $this->username = Url::toShort($mobile . microtime());
        $this->setMobile($mobile);
    }

    /**
     * 根据OAuth2.0第三方平台的openid生成系统唯一用户名
     * @param string $client 第三方平台
     * @param string $openid openid
     */
    public function setUsernameByOpenid($client, $openid) {
        $this->username = Url::toShort($client . $openid . microtime());
    }

    /**
     * 设置手机号（自动加密）
     * @param string $mobile 手机号
     */
    public function setMobile($mobile) {
        if ($mobile) {
            /* @var $security \common\base\Security */
            $security = Yii::$app->security;
            $this->mobile = $security->generatePrivateKey($mobile);
        }
    }

    /**
     * 手机号解密
     * @param boolean $mask 是否屏蔽手机号部分信息
     */
    public function decryptMobile($mask = true) {
        $mobile = Yii::$app->security->decryptMaster('');
        if ($mask !== false) {
            return StringHelper::maskChar($mobile, 3, 2);
        }
        return $mobile;
    }

    /**
     * 获取头像URL
     * @return string
     */
    public function getPortrait() {
        $avatar = $this->avatar ?: ArrayHelper::getValue(Yii::$app->params, 'defaultImages.admin_avatar', '/assets/avatar/default.png');
        return Url::attach($avatar);
    }

    /**
     * 生成auth_key
     */
    public function generateAuthKey() {
        $this->auth_key = Yii::$app->security->generateRandomString();
    }

    /**
     * 生成密码重置token
     */
    public function generatePasswordResetToken() {
        $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
    }

    /**
     * 生成access_token
     */
    public function generateAccessToken() {
        do {
            $token = Yii::$app->security->generateRandomString();
            $record = static::find()->where(['access_token' => $token])->exists();
        } while ($record);
        $this->access_token = $token;
        $this->expired_at = time() + self::TOKEN_EXPIRED;
    }

    /**
     * 刷新access_token
     */
    public function refreshAccessToken() {
        if ($this->validateAccessTokenAvailabled()) {
            $this->generateAccessToken();
        } else {
            $this->delayAccessTokenExpireTime();
        }
    }

    /**
     * 校验access_token是否过期
     */
    public function validateAccessTokenAvailabled() {
        return $this->expired_at < time();
    }

    /**
     * 延时access_token过期时间
     */
    public function delayAccessTokenExpireTime() {
        $delayTime = max($this->expired_at - time(), self::TOKEN_EXPIRED_DELAY);
        $this->expired_at = time() + $delayTime;
    }

    /**
     * 移除密码重置token
     */
    public function removePasswordResetToken() {
        $this->password_reset_token = null;
    }

    /**
     * 移除密码重置token
     */
    public function removeAccessToken() {
        $this->access_token = null;
        $this->expired_at = 0;
    }

    /**
     * 获取认证用户信息
     * @inheritdoc
     */
    public function getUserAuthent() {
        return $this->hasOne(UserAuthent::className(), ['user_id' => 'id']);
    }

    /**
     * 获取用户基础信息
     * @inheritdoc
     */
    public function getMeta() {
        return $this->hasOne(UserMeta::className(), ['id' => 'id']);
    }

}
